package nl.unimaas.micc.umsnooker.domain;

import java.util.HashSet;

import nl.unimaas.micc.umsnooker.domain.Ball.BallState;
import nl.unimaas.micc.umsnooker.simulation.event.BallCollision;
import nl.unimaas.micc.umsnooker.simulation.event.Event;
import nl.unimaas.micc.umsnooker.simulation.physics.Physics;

import com.jme.math.Vector3f;

public class BilliardBall extends Ball
{
	public enum Type
	{
		CUE(0), 
		RED(1),
		YELLOW(2), 
		GREEN(3), 
		BROWN(4),
		BLUE(5),
		PINK(6), 
		BLACK(7);

		private int value;
		Type(int value)
		{
			this.value = value;
		}
		
		public int getValue()
		{
			return value;
		}
	}

	private int id;
	private Type type;
	
	public BilliardBall(int id, Type type)
	{
		this.id = id;
		this.type = type;
	}
	
	public BilliardBall(int id, Type type, Vector3f position)
	{
		this(id, type);
		setPosition(position);
	}
	
	public BilliardBall(int id)
	{
		this(id, Type.RED);
	}
	
	public int getID()
	{
		return id;
	}
	
	public void setID(int id)
	{
		this.id = id;
	}
	
	public Type getType()
	{
		return type;
	}
	
	public void setType(Type type)
	{
		this.type = type;
	}

	@Override
	public boolean equals(Object b2)
	{
		return ((BilliardBall) b2).getID() == id;
	}

	
	@Override
	public int hashCode()
	{
		return id;
	}
	

	@Override
	public Object clone()
	{
		BilliardBall copy = new BilliardBall(id, type);
		copy.setPosition(getPosition().clone());
		copy.setVelocity(getVelocity().clone());
		copy.setAngularVelocity(getAngularVelocity().clone());
		copy.setRadius(getRadius());
		copy.setMass(getMass());
		copy.setTime(getTime());
		copy.setState(getState());
		return copy;
	}
	
	@Override
	public String toString()
	{
		return "b["+id+","+type.toString() + super.toString()+"]";
	}
	
	@Override
	public Event findCollision(BilliardBall b)
	{
		if (!b.equals(this) && !(b.getState() == BallState.RESTING && this.getState() == BallState.RESTING))
		{
			float maxTime = Math.max(b.getTime(), this.getTime());

			Ball advanced = null, initial = null, other = null;

			if (b.getTime() < maxTime)
			{
				advanced = (BilliardBall) b.clone();
				initial = b;
				other = this;
			}
			else if (this.getTime() < maxTime)
			{
				advanced = (BilliardBall) this.clone();
				initial = this;
				other = b;
			}
			else
			{
				advanced = b;
				other = this;
			}

			if (advanced != null && initial != null)
			{
				advanced.setPosition(advanced.getState().getMotion()
						.getPosition(initial, maxTime));
				advanced.setVelocity(advanced.getState().getMotion()
						.getVelocity(initial, maxTime));
				advanced.setAngularVelocity(advanced.getState().getMotion()
						.getAngularVelocity(initial, maxTime));
			}

			float t = Physics.collisionTime(advanced, other);
			if (t >= 0)
			{
				HashSet<BilliardBall> h = new HashSet<BilliardBall>();
				h.add(b);
				h.add(this);
				return new BallCollision(maxTime + t, h);
				
			}
			else
			{
				return null;
			}

		}
		return null;
	}


}
